#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ls (x << 1)
#define rs (x << 1 | 1)
using namespace std;

const int N = 1e5 + 10, INF = 0x3f3f3f3f;

int n, m, rt, mod, cnt;
vector<int> g[N];
int val[N], fa[N], dep[N], siz[N], son[N], dfn[N], top[N], seg[N];

struct node {
    int l, r; ll sum, lazy;
    int len() { return r - l + 1; }
}tr[N << 2];

void pushup(int x) { tr[x].sum = (tr[ls].sum + tr[rs].sum) % mod; }
void pushdown(int x) {
    if (tr[x].lazy) {
        (tr[ls].lazy += tr[x].lazy) %= mod;
        (tr[rs].lazy += tr[x].lazy) %= mod;
        (tr[ls].sum += tr[x].lazy * tr[ls].len() % mod) %= mod;
        (tr[rs].sum += tr[x].lazy * tr[rs].len() % mod) %= mod;
        tr[x].lazy = 0;
    }
}

void build(int x, int l, int r)
{
    tr[x].l = l, tr[x].r = r;
    tr[x].lazy = 0;
    if (l == r) {
        tr[x].sum = val[seg[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(ls, l, mid);build(rs, mid + 1, r);
    pushup(x);
}

void modify(int x, int l, int r, ll d)
{
    if (l <= tr[x].l && tr[x].r <= r) {
        (tr[x].sum += d * tr[x].len() % mod) %= mod;
        (tr[x].lazy += d) %= mod;
        return;
    }
    pushdown(x);
    int mid = (tr[x].l + tr[x].r) >> 1;
    if (l <= mid) modify(ls, l, r, d);
    if (r > mid) modify(rs, l, r, d);
    pushup(x);
}

ll query(int x, int l, int r)
{
    if (l <= tr[x].l && tr[x].r <= r) return tr[x].sum;
    pushdown(x);
    int mid = (tr[x].l + tr[x].r) >> 1;ll ans = 0;
    if (l <= mid) (ans += query(ls, l, r)) %= mod;
    if (r > mid) (ans += query(rs, l, r)) %= mod;
    return ans;
}

int dfs1(int x, int f)
{
    fa[x] = f;siz[x] = 1;
    dep[x] = dep[f] + 1;
    for (int y : g[x]) {
        if (y == f) continue;
        siz[x] += dfs1(y, x);
        if (son[x] == 0 || siz[son[x]] < siz[y]) son[x] = y;
    }
    return siz[x];
}

void dfs2(int x, int t)
{
    top[x] = t;
    dfn[x] = ++cnt;seg[cnt] = x;
    if (son[x] == 0) return;
    dfs2(son[x], t);
    for (int y : g[x]) {
        if (y == fa[x] || y == son[x]) continue;
        dfs2(y, y);
    }
}

void pathadd(int x, int y, int d)
{
    while (top[x] != top[y]) {
        if (dep[top[x]] >= dep[top[y]]) {
            modify(1, dfn[top[x]], dfn[x], d);
            x = fa[top[x]];
        } else {
            modify(1, dfn[top[y]], dfn[y], d);
            y = fa[top[y]];
        }
    }
    modify(1, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]), d);
}

ll pathask(int x, int y)
{
    ll ans = 0;
    while (top[x] != top[y]) {
        if (dep[top[x]] >= dep[top[y]]) {
            (ans += query(1, dfn[top[x]], dfn[x])) %= mod;
            x = fa[top[x]];
        } else {
            (ans += query(1, dfn[top[y]], dfn[y])) %= mod;
            y = fa[top[y]];
        }
    }
    return (ans + query(1, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]))) % mod;
}

void subadd(int x, int d) { modify(1, dfn[x], dfn[x] + siz[x] - 1, d); }
ll subask(int x) { return query(1, dfn[x], dfn[x] + siz[x] - 1); }

void solve()
{
    cin >> n >> m >> rt >> mod;
    for (int i = 1;i <= n;i++) {
        cin >> val[i];
        (val[i] += mod) %= mod;
    }
    for (int i = 1;i < n;i++) {
        int x, y;cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    dfs1(rt, 0);dfs2(rt, rt);
    build(1, 1, cnt);

    int op, x, y, z;
    while (m--) {
        cin >> op;
        if (op == 1) {
            cin >> x >> y >> z;
            pathadd(x, y, (z + mod) % mod);
        } else if (op == 2) {
            cin >> x >> y;
            cout << pathask(x, y) << '\n';
        } else if (op == 3) {
            cin >> x >> z;
            subadd(x, (z + mod) % mod);
        } else {
            cin >> x;
            cout << subask(x) << '\n';
        }
    }
}

signed main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
#define ONLINE_JUDGE
#ifndef ONLINE_JUDGE
    std::istringstream in(R"()");
    std::cin.rdbuf(in.rdbuf());
#endif
    int T = 1;
    //cin>>T;
    for (int i = 1;i <= T;i++) {
        solve();
    }
}